#region

using SqlSugar;

#endregion

namespace Vin.Extension.SqlSugar;

public class VinAopProvider
{
    private Action<ISqlSugarClient, DiffLogModel>? _onDiffLogEvent;

    public Action<ISqlSugarClient, DiffLogModel>? OnDiffLogEvent
    {
        get => _onDiffLogEvent;
        set => _onDiffLogEvent += value;
    }

    private Action<ISqlSugarClient, SqlSugarException>? _onError;

    public Action<ISqlSugarClient, SqlSugarException>? OnError
    {
        get => _onError;
        set => _onError += value;
    }

    private Action<ISqlSugarClient, string, SugarParameter[]>? _onLogExecuting;

    public Action<ISqlSugarClient, string, SugarParameter[]>? OnLogExecuting
    {
        get => _onLogExecuting;
        set => _onLogExecuting += value;
    }

    private Action<ISqlSugarClient, string, SugarParameter[]>? _onLogExecuted;

    public Action<ISqlSugarClient, string, SugarParameter[]>? OnLogExecuted
    {
        get => _onLogExecuted;
        set => _onLogExecuted += value;
    }

    private Action<ISqlSugarClient, object, DataFilterModel>? _dataExecuting;

    public Action<ISqlSugarClient, object, DataFilterModel>? DataExecuting
    {
        get => _dataExecuting;
        set => _dataExecuting += value;
    }

    private Action<ISqlSugarClient, object, DataAfterModel>? _dataExecuted;

    public Action<ISqlSugarClient, object, DataAfterModel>? DataExecuted
    {
        get => _dataExecuted;
        set => _dataExecuted += value;
    }

    private List<Func<ISqlSugarClient, string, SugarParameter[], KeyValuePair<string, SugarParameter[]>>>
        _onExecutingChangeSql = new();

    public List<Func<ISqlSugarClient, string, SugarParameter[], KeyValuePair<string, SugarParameter[]>>>
        OnExecutingChangeSql =>
        _onExecutingChangeSql;

    public void AddOnExecutingChangeSql(
        Func<ISqlSugarClient, string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> func) =>
        _onExecutingChangeSql.Add(func);
}

public class VinSqlSugarClient : SqlSugarClient
{
    public VinAopProvider VinAop { get; set; } = new VinAopProvider();

    public VinSqlSugarClient(ConnectionConfig config) : base(config)
    {
        InitAop();
    }

    public VinSqlSugarClient(List<ConnectionConfig> configs) : base(configs)
    {
        InitAop();
    }

    public VinSqlSugarClient(ConnectionConfig config, Action<VinSqlSugarClient> configAction) : this(config)
    {
        InitAop();
        configAction(this);
    }

    public VinSqlSugarClient(List<ConnectionConfig> configs, Action<VinSqlSugarClient> configAction) : this(configs)
    {
        InitAop();
        configAction(this);
    }

    private void InitAop()
    {
        Aop.OnDiffLogEvent = (log) => VinAop.OnDiffLogEvent?.Invoke(this, log);
        Aop.OnError = (ex) => VinAop.OnError?.Invoke(this, ex);
        Aop.OnLogExecuting = (sql, pars) => VinAop.OnLogExecuting?.Invoke(this, sql, pars);
        Aop.OnLogExecuted = (sql, pars) => VinAop.OnLogExecuted?.Invoke(this, sql, pars);
        Aop.DataExecuting = (obj, filter) => VinAop.DataExecuting?.Invoke(this, obj, filter);
        Aop.DataExecuted = (obj, after) => VinAop.DataExecuted?.Invoke(this, obj, after);
        Aop.OnExecutingChangeSql = (sql, pars) =>
        {
            var result = new KeyValuePair<string, SugarParameter[]>(sql, pars);
            foreach (var changeFunc in VinAop.OnExecutingChangeSql)
            {
                result = changeFunc.Invoke(this, result.Key, result.Value);
            }

            return result;
        };
    }
}